﻿using OpenTK.Mathematics;
using System.Runtime.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Core.Log;
using Newtonsoft.Json.Linq;

namespace Core.ECS.Components
{
    [DataContract]
    public class CTransform : IComponent
    {
        public Guid Id { get => _id; set => _id = value; }
        public Actor Actor => Actor.GetActor(_id);

        [DataMember]
        public CTransform Parent
        {
            get => _parent;
            set
            {
                Matrix4 matrix = WorldMatrix;
                if (_parent != null && _parent.Children != null)
                {
                    _parent.Children.Remove(this);
                }
                _parent = value;
                if (value != null)
                {
                    if (value.Children != null)
                    {
                        value.Children.Add(this);
                    }
                    else
                    {
                        value.Children = new List<CTransform>();
                        value.Children.Add(this);
                    }
                    LocalMatrix = matrix * Matrix4.Invert(value.WorldMatrix);
                }
                else
                {
                    LocalMatrix = matrix;
                }
            }
        }
        public List<CTransform> Children
        {
            get
            {
                if (_children == null)
                {
                    _children = new List<CTransform>();
                }
                return _children;
            }
            set { _children = value; }
        }
        private List<CTransform> _children;
        private CTransform _parent;
        public Vector3 LocalPosition
        {
            get => GetLocalPosition();
            set => SetLocalPosition(value);
        }
        public Vector3 LocalEulerAngle
        {
            get
            {
                _localEulerAngle = LocalRotation.ToEulerAngles() * 180 /MathHelper.Pi;
                return _localEulerAngle;
            }
            set 
            { 
                _localEulerAngle = value;
                LocalRotation = Quaternion.FromEulerAngles(value * MathHelper.Pi / 180); 
            }
        }
        public Quaternion LocalRotation
        {
            get => GetLocalRotation();
            set => SetLocalRotation(value);
        }
        public Vector3 LocalScale
        {
            get => GetLocalScale();
            set => SetLocalScale(value);
        }
        public Matrix4 LocalMatrix
        {
            get => GetLocalMatrix();
            set => SetLocalMatrix(value);
        }
        public Matrix4 WorldMatrix
        {
            get => GetWorldMatrix();
        }
        public Vector3 WorldPosition => GetWorldPosition();
        public Quaternion WorldRotation => GetWorldRotation();
        public Vector3 WorldScale => GetWorldScale();

        [DataMember] private Guid _id;
        [DataMember] private Vector3 _localPosition;
        [DataMember] private Vector3 _localEulerAngle;
        private Quaternion _localRotation;
        [DataMember] private Vector3 _localScale;
        private Matrix4 _localMatrix;
        private Matrix4 _worldMatrix;
        [DataMember] private bool _isDirty = false;//因为无法确定父物体是否移动，_isDirty只关系自己是否改变，不关心父物体是否改变，因此每次计算世界矩阵都需要Update
        [OnSerializing]
        public void OnSerializing(StreamingContext _)
        {

        }
        [OnSerialized]
        public void OnSerialized(StreamingContext _)
        {

        }
        [OnDeserializing]
        public void OnDeserializing(StreamingContext _)
        {

        }
        [OnDeserialized]
        public void OnDeserialized(StreamingContext _)
        {
            _localRotation = Quaternion.FromEulerAngles(_localEulerAngle * MathHelper.Pi / 180);
            _isDirty = true;
            //if(Parent != null && Parent.Actor != null)
            //{
            //    Parent = Parent.Actor.Transform;
            //}
            UpdateMatrices();
        }
        public CTransform(Guid id)
        {
            _parent = null;
            _children = new();
            _id = id;
            _localPosition = new Vector3();
            _localRotation = Quaternion.Identity;
            _localScale = Vector3.One;
            _localMatrix = Matrix4.Identity;
            _worldMatrix = Matrix4.Identity;
        }
        public void UpdateParent()
        {
            if(_parent != null )
            {
                _parent = _parent.Actor.Transform;
                _parent.Children.Add(this);
            }
        }
        public void Rotate(Vector3 rotationShaft, float rotationAngle)
        {
            LocalRotation *= Quaternion.FromAxisAngle(rotationShaft, MathHelper.DegreesToRadians(rotationAngle));
        }
        public void SetLocalPosition(Vector3 localPosition)
        {
            _localPosition = localPosition;
            _isDirty = true;
            if (Children?.Count > 0)
            {
                UpdateMatrices();
            }
        }
        public void SetLocalRotation(Quaternion localRotation)
        {
            _localRotation = localRotation;
            _isDirty = true;
            if (Children?.Count > 0)
            {
                UpdateMatrices();
            }
        }
        public void SetLocalScale(Vector3 localScale)
        {
            _localScale = localScale;
            _isDirty = true;
            if (Children?.Count > 0)
            {
                UpdateMatrices();
            }
        }
        public Vector3 GetLocalPosition() => _localPosition;
        public Quaternion GetLocalRotation() => _localRotation;
        public Vector3 GetLocalScale() => _localScale;
        private void UpdateMatrices()
        {
            if (_isDirty)
            {
                _localMatrix = Matrix4.CreateScale(_localScale)
                    * Matrix4.CreateFromQuaternion(_localRotation)
                    * Matrix4.CreateTranslation(_localPosition);
            }
            if (Parent == null)
            {
                _worldMatrix = _localMatrix;
            }
            else
            {
                _worldMatrix = Parent.WorldMatrix * _localMatrix;
            }
            _isDirty = false;
        }
        public void SetWordMatrix(Matrix4 parentTransform)
        {
            if (_isDirty)
            {
                UpdateMatrices();
            }
            //_parentMatrix = parentTransform;
            _worldMatrix = parentTransform * _localMatrix;
        }
        public void SetLocalMatrix(Matrix4 localMatrix)
        {
            _localMatrix = localMatrix;
            if (Parent == null)
            {
                _worldMatrix = _localMatrix;
            }
            else
            {
                _worldMatrix = Parent.WorldMatrix * _localMatrix;
            }
            ApplyTransform();
        }
        public Matrix4 GetLocalMatrix()
        {
            if (_isDirty)
            {
                UpdateMatrices();
            }
            return _localMatrix;
        }
        public Matrix4 GetWorldMatrix()
        {
            if (_isDirty)
            {
                UpdateMatrices();
            }
            return _worldMatrix;
        }
        public Vector3 GetWorldPosition()
        {
            UpdateMatrices();
            return _worldMatrix.ExtractTranslation();
        }
        public Quaternion GetWorldRotation()
        {
            UpdateMatrices();
            return _worldMatrix.ExtractRotation();
        }
        public Vector3 GetWorldScale()
        {
            UpdateMatrices();
            return _worldMatrix.ExtractScale();
        }
        private void ApplyTransform()
        {
            _localPosition = _localMatrix.ExtractTranslation();
            _localRotation = _localMatrix.ExtractRotation();
            _localScale = _localMatrix.ExtractScale();
            _isDirty = false;
        }
    }
}